home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / boot / netBoot.new / sys / tftp.c < prev    next >
C/C++ Source or Header  |  1990-12-19  |  6KB  |  240 lines

  1.  
  2. /*
  3.  * @(#)tftp.c 1.1 86/09/27
  4.  * Copyright (c) 1986 by Sun Microsystems, Inc.
  5.  */
  6.  
  7. /*
  8.  * Standalone network boot via TFTP
  9.  */
  10. #include "../dev/saio.h"
  11. #include "../h/socket.h"
  12. #include "../dev/if.h"
  13. #include "../h/in.h"
  14. #include "../dev/if_ether.h"
  15. #include "../h/in_systm.h"
  16. #include "../h/ip.h"
  17. #include "../h/udp.h"
  18. #include "../h/sainet.h"
  19. #include "../h/sunromvec.h"
  20. #include "../sun3/cpu.addrs.h"
  21. #undef DEV_BSIZE
  22. #undef MAX
  23. #include "../h/tftp.h"
  24.  
  25.  
  26. char    *tftp_errs[] = {
  27.     "not defined",
  28.     "file not found",
  29.     "access violation",
  30.     "disk full or allocation exceeded",
  31.     "illegal TFTP operation",
  32.     "unknown transfer ID",
  33.     "file already exists",
  34.     "no such user"
  35. };
  36.  
  37.  
  38. #define       LOADADDR        0x4000
  39. #define millitime() (*romp->v_nmiclock)
  40.  
  41. struct tftp_pack {    /* TFTP packet */
  42.     struct ether_header tf_ether;    /* Ethernet header */
  43.     struct ip tf_ip;        /* IP header */
  44.     struct udphdr tf_udp;        /* UDP header */
  45.     struct tftphdr tf_tftp;        /* TFTP header */
  46.     char tftp_data[SEGSIZE];    /* TFTP data beyond header */
  47. };
  48.  
  49. /*
  50.  * Size of Headers in TFTP DATA packet
  51.  */
  52. #define TFTPHDRLEN    (sizeof (struct ether_header) + sizeof (struct ip) + \
  53.              sizeof (struct udphdr) + 4)
  54.  
  55. struct tftpglob {
  56.     struct tftp_pack tf_out;    /* outgoing TFTP packet */
  57.     struct sainet tf_inet;        /* Internet state */
  58.     char    tf_tmpbuf[1600];    /* tmp for incoming packets */
  59.     int    tf_block;        /* current block number */
  60.     char    *tf_data;        /* current load pointer */
  61. };
  62.  
  63. #define TFTPBASE    ((struct tftpglob *)0x3000)
  64.  
  65. #define    REXMIT_MSEC    4000    /* 4 seconds between retransmits */
  66.  
  67. etheropen(sip)
  68.     register struct saioreq *sip;
  69. {
  70.     register struct tftpglob *tf = TFTPBASE;
  71.  
  72.     bzero((caddr_t)tf, sizeof (*tf));
  73.     inet_init(sip, &tf->tf_inet, tf->tf_tmpbuf); /* Initialize inet */
  74.     return (0);
  75. }
  76.  
  77. etherstrategy(sip, rw)
  78.     register struct saioreq *sip;
  79.     int rw;
  80. {
  81.     printf("tftp: random access attempted - code error.\n");
  82.     return (-1);
  83. }
  84.  
  85. tftpload(sip)
  86.     register struct saioreq *sip;
  87. {
  88.     register struct tftpglob *tf = TFTPBASE;
  89.     register struct tftp_pack *out = &tf->tf_out;
  90.     register struct tftp_pack *in = (struct tftp_pack *)tf->tf_tmpbuf;
  91.     register char *p, *q, *x;
  92.     register short i, len;
  93.     int autoboot = 0;
  94.     int firsttry = 0;
  95.     int feedback = 0;
  96.     int time, xcount, locked, retry;
  97.     char    *ind = "-\\|/";
  98.  
  99.     if (sip->si_unit == 0)
  100.                 autoboot = 1;    /* if unit # is 0, this is an autoboot */
  101. top:
  102.     /*
  103.      * Initialize IP and UDP headers
  104.      */
  105.     out->tf_ip.ip_v = IPVERSION;
  106.     out->tf_ip.ip_hl = sizeof (struct ip) / 4;
  107.     out->tf_ip.ip_ttl = MAXTTL;
  108.     out->tf_ip.ip_p = IPPROTO_UDP;
  109.     out->tf_udp.uh_sport =  (millitime() & 1023) + 1024;
  110.     out->tf_udp.uh_dport =  IPPORT_TFTP;
  111.     out->tf_udp.uh_sum =  0;        /* no checksum */
  112.      
  113.     /* 
  114.      * Set src and dst host addresses
  115.      * Dst host is argument with our net number plugged in
  116.      */
  117.     out->tf_ip.ip_src = tf->tf_inet.sain_myaddr;
  118.  
  119.     if (autoboot && firsttry == 0) {
  120.             out->tf_ip.ip_dst.s_addr = tf->tf_inet.sain_hisaddr.s_addr;
  121.     } else if (autoboot && firsttry > 0) {
  122.         out->tf_ip.ip_dst.s_addr = -1;
  123.     } else {
  124.         out->tf_ip.ip_dst.s_addr = out->tf_ip.ip_src.s_addr +
  125.                 sip->si_unit  - in_lnaof(out->tf_ip.ip_src);
  126.     }
  127.  
  128.     ++firsttry;
  129.     locked = 0;
  130.     retry = 0;
  131.     tf->tf_block = 1;
  132.     tf->tf_data = (char *)LOADADDR;
  133.  
  134.     /*
  135.      * Create the TFTP Read Request packet 
  136.      */
  137.     out->tf_tftp.th_opcode = RRQ;
  138.     p = out->tf_tftp.th_stuff;
  139.     q = (char *)&tf->tf_inet.sain_myaddr;
  140.     x = "0123456789ABCDEF";
  141.     for (i=0; i<4; i++) {
  142.         *p++ = x[(*q >> 4) & 0xF];
  143.         *p++ = x[(*q++) & 0xF];
  144.     }
  145.     *p++ = 0;
  146.     q = "octet";
  147.     while (*p++ = *q++)
  148.         ;
  149.     out->tf_udp.uh_ulen = sizeof (struct udphdr) + 2 +
  150.         (p - out->tf_tftp.th_stuff);
  151.     out->tf_ip.ip_len = sizeof (struct ip) +
  152.         out->tf_udp.uh_ulen;
  153.     
  154.     time = 0;
  155.     for (xcount = 0; xcount < 5;) {
  156.         if (millitime() - time >= REXMIT_MSEC) {
  157.             time = millitime();
  158.             printf("%c\b", ind[feedback++ % 4]); /* Show activity */
  159.             if (ip_output(sip, (caddr_t)out, out->tf_ip.ip_len +
  160.                 sizeof (struct ether_header), &tf->tf_inet,
  161.                 tf->tf_tmpbuf))
  162.                 printf("X\b");
  163.             if (locked == 0 || retry > 15)
  164.                 xcount++;
  165.             else 
  166.                 retry++;
  167.         }
  168.         len = ip_input(sip, (caddr_t)in, &tf->tf_inet);
  169.         if (len < TFTPHDRLEN)
  170.             continue;
  171.         if (in->tf_ip.ip_p != IPPROTO_UDP ||
  172.             in->tf_udp.uh_dport != out->tf_udp.uh_sport) 
  173.             continue;
  174.         if (locked &&
  175.                     out->tf_ip.ip_dst.s_addr != in->tf_ip.ip_src.s_addr)                                continue;
  176.         if (in->tf_tftp.th_opcode == ERROR) {
  177.             if (autoboot && tf->tf_block == 1)
  178.                 continue;
  179.             if (in->tf_tftp.th_code < 0 ||
  180.                 in->tf_tftp.th_code > sizeof(tftp_errs)/sizeof(char *)){
  181.                 printf("tftp: Unknown error 0x%x\n",
  182.                     in->tf_tftp.th_code);
  183.             } else {
  184.                 printf("tftp: %s @ block %d\n",
  185.                     tftp_errs[in->tf_tftp.th_code], tf->tf_block);
  186.             }
  187.             if (autoboot)
  188.                 goto top;
  189.             return (-1);
  190.         }
  191.         if (in->tf_tftp.th_opcode != DATA ||
  192.             in->tf_tftp.th_block != tf->tf_block) 
  193.             continue;
  194.         /*
  195.          * Here if we have an in sequence DATA packet
  196.          */
  197.         if (tf->tf_block == 1) {    /* lock on to server and port */
  198.             out->tf_udp.uh_dport = in->tf_udp.uh_sport;
  199.             if (autoboot) 
  200.                 out->tf_ip.ip_dst = in->tf_ip.ip_src;
  201.             printf("Booting from tftp server at "); 
  202.                         inet_print(out->tf_ip.ip_dst);
  203.             locked = 1;
  204.         }
  205.         /*
  206.          * Swallow data
  207.          */
  208.         len = in->tf_udp.uh_ulen - (sizeof(struct udphdr) + 4);
  209.         if (len) {
  210.             bcopy(in->tf_tftp.th_data, tf->tf_data, len);
  211.             tf->tf_data += len;
  212.         }
  213.         /*
  214.          * Send ACK 
  215.          */
  216.         xcount = 0;
  217.         retry = 0;
  218.         out->tf_tftp.th_opcode = ACK;
  219.         out->tf_tftp.th_block = tf->tf_block++;
  220.         out->tf_udp.uh_ulen = sizeof (struct udphdr) + 4;
  221.         out->tf_ip.ip_len = sizeof (struct ip) + out->tf_udp.uh_ulen;
  222.         time = millitime();
  223.         printf("%c\b", ind[feedback++ % 4]);    /* Show activity */
  224.         if (ip_output(sip, (caddr_t)out, out->tf_ip.ip_len +
  225.             sizeof (struct ether_header), &tf->tf_inet,
  226.             tf->tf_tmpbuf))
  227.             printf("X\b");
  228.         if (len < SEGSIZE) {     /* end of file */
  229.             printf("Downloaded %d bytes from tftp server.\n\n",
  230.                 tf->tf_data - LOADADDR);
  231.             return (LOADADDR);
  232.         }
  233.     }
  234.     printf("tftp: time-out.\n");
  235.     if (autoboot)
  236.         goto top;
  237.     return (-1);
  238. }
  239.  
  240.